/**
 *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)]
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License. 
 *You may obtain a copy of the License at 
 *             http://www.apache.org/licenses/LICENSE-2.0 
 *Unless required by applicable law or agreed to in writing, 
 *software distributed under the License is distributed on an "AS IS" BASIS, 
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
 *either express or implied. See the License for the specific language governing permissions and limitations under the License
 */
/**
 *Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)]
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *             http://www.apache.org/licenses/LICENSE-2.0
 *Unless required by applicable law or agreed to in writing,
 *software distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 *either express or implied. See the License for the specific language governing permissions and limitations under the License
 */
package com.bj58.ecdata.redis.transcoders;

import com.bj58.ecdata.redis.exception.JedisXException;

/**
 * Transcoder for TokyoTyrant.Add 4-bytes flag before value.
 *
 * @author boyan
 */
public class TokyoTyrantTranscoder implements Transcoder<Object> {
    private final SerializingTranscoder serializingTranscoder;

    public TokyoTyrantTranscoder(int maxSize) {
        serializingTranscoder = new SerializingTranscoder(maxSize);
        serializingTranscoder.setPackZeros(false);
    }

    public TokyoTyrantTranscoder() {
        serializingTranscoder = new SerializingTranscoder();
        serializingTranscoder.setPackZeros(false);
    }

    public final Object decode(CachedData d) throws JedisXException {
        byte[] compositeData = d.getData();
        if (compositeData.length <= 4)
            throw new JedisXException(
                    "There are no four bytes before value for TokyoTyrantTranscoder");
        byte[] flagBytes = new byte[4];
        byte[] realData = new byte[compositeData.length - 4];
        System.arraycopy(compositeData, 0, flagBytes, 0, 4);
        System.arraycopy(compositeData, 4, realData, 0,
                compositeData.length - 4);
        int flag = serializingTranscoder.getTranscoderUtils().decodeInt(
                flagBytes);
        d.setFlag(flag);
        if ((flag & SerializingTranscoder.COMPRESSED) != 0) {
            realData = serializingTranscoder.decompress(realData);
        }
        flag = flag & SerializingTranscoder.SPECIAL_MASK;
        return serializingTranscoder.decode0(d, realData, flag);
    }


    public void setCompressionMode(CompressionMode compressMode) {
        this.serializingTranscoder.setCompressionMode(compressMode);
    }

    public final CachedData encode(Object o) {
        CachedData result = serializingTranscoder.encode(o);
        byte[] realData = result.getData();
        int flag = result.getFlag();
        byte[] flagBytes = serializingTranscoder.getTranscoderUtils()
                .encodeInt(flag);

        byte[] compisiteData = new byte[4 + realData.length];
        System.arraycopy(flagBytes, 0, compisiteData, 0, 4);
        System.arraycopy(realData, 0, compisiteData, 4, realData.length);

        result.setData(compisiteData);
        return result;
    }

    public final int getMaxSize() {
        return serializingTranscoder.getMaxSize();
    }

    public boolean isPackZeros() {
        return serializingTranscoder.isPackZeros();
    }

    public boolean isPrimitiveAsString() {
        return serializingTranscoder.isPrimitiveAsString();
    }

    public void setCharset(String to) {
        serializingTranscoder.setCharset(to);
    }

    public void setCompressionThreshold(int to) {
        serializingTranscoder.setCompressionThreshold(to);
    }

    public void setPackZeros(boolean packZeros) {
        throw new UnsupportedOperationException(
                "TokyoTyrantTranscoder doesn't support pack zeros");
    }

    public void setPrimitiveAsString(boolean primitiveAsString) {
        throw new UnsupportedOperationException(
                "TokyoTyrantTranscoder doesn't support save primitive type as String");
    }
}
